package com.hs.device.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.hs.common.api.dto.PageBean;
import com.hs.device.constant.DeviceConstant;
import com.hs.device.constant.OrderConstant;
import com.hs.device.dto.DetectorDto;
import com.hs.device.dto.UpdateDetectorDto;
import com.hs.device.entity.Detector;
import com.hs.device.exception.Asserts;
import com.hs.feign.dto.Orders;
import com.hs.device.mapper.DetectorMapper;
import com.hs.device.service.IDetectorService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hs.common.api.dto.ResultCode;
import com.hs.common.api.dto.ResultVo;
import com.hs.feign.client.OrderClient;
import com.hs.feign.dto.OrderDto;
import com.hs.pk.berth.client.BerthFeignClient;
import com.hs.pk.berth.client.dto.RoadBerthDto;
import com.hs.device.exception.Asserts;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.*;

/**
 * <p>
 * detector 服务实现类
 * </p>
 *
 * @author Ding
 * @since 2022-07-20
 */
@Service
public class DetectorServiceImpl extends ServiceImpl<DetectorMapper, Detector> implements IDetectorService {

    @Autowired
    private DetectorMapper detectorMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private BerthFeignClient berthFeignClient;
    @Autowired
    private OrderClient orderClient;

    /**
     * 条件查询
     * @param deviceId
     * @param deviceName
     * @param berthId
     * @return
     */
    @Override
    public ResultVo findDeviceByConditions(Integer current,Integer size,Long deviceId, String deviceName, Integer berthId) {

        LambdaQueryWrapper<Detector> query = Wrappers.lambdaQuery(Detector.class);

        //        判断参数是否为空
        if (deviceId != null){
            query.eq(Detector::getId,deviceId);
        }
        if (StringUtils.hasText(deviceName)){
            query.eq(Detector::getName,deviceName);
        }
        if (berthId != null){
            query.eq(Detector::getBerthId,berthId);
        }

        Page<Detector> page = new Page<>(current, size);
        Page<Detector> detectorPage = detectorMapper.selectPage(page, query);
        Long total = detectorPage.getTotal();
        List<Detector> records = detectorPage.getRecords();

        if (!CollectionUtils.isEmpty(records)) {
            PageBean pageBean = new PageBean();
            pageBean.setTotals(total.intValue());
            pageBean.setList(records);

            return new ResultVo(pageBean);
        }

        return new ResultVo(ResultCode.FAILED);


    }

    /**
     * 添加地磁设备
     * @param detectorDto
     * @return
     */
    @Override
    public ResultVo addDetector(DetectorDto detectorDto) {

        Detector detector = new Detector();
        detector.setBuildTime(new Date());
        detector.setStatus(1);
        detector.setHaveCar(0);
        BeanUtils.copyProperties(detectorDto,detector);


        int insert = detectorMapper.insert(detector);

        if (insert > 0){
            return new ResultVo("地磁设备添加成功");
        }else{
            return new ResultVo(ResultCode.FAILED,"地磁设备添加失败");
        }
    }

    /**
     * 修改地磁设备信息
     * @param updateDetectorDto
     * @return
     */
    @Override
    public ResultVo updateDevice(UpdateDetectorDto updateDetectorDto) {

        Long id = updateDetectorDto.getId();
        Detector detector = detectorMapper.selectById(id);

        Long berthId = detector.getBerthId();


        if(berthId == null){

            BeanUtils.copyProperties(updateDetectorDto,detector);
            detector.setBuildTime(new Date());
            detector.setStatus(1);
            detector.setHaveCar(0);

            int update = detectorMapper.updateById(detector);

            if (update > 0){
                return new ResultVo(ResultCode.SUCCESS,"地磁设备修改成功");
            }else{
                return new ResultVo(ResultCode.FAILED,"地磁设备修改失败");
            }

        }else{
            return new ResultVo(ResultCode.FAILED,"地磁已绑定泊车位，无法修改");
        }




    }

    @Override
    public ResultVo deleteDevice(Integer detectorId) {

        Detector detector = detectorMapper.selectById(detectorId);
        Long berthId = detector.getBerthId();

        if(berthId == null){

            int delete = detectorMapper.deleteById(detectorId);

            //调用 修改泊车位信息 接口，将所关联的泊车位的地磁信息删除掉

            if (delete > 0){
                return new ResultVo(ResultCode.SUCCESS,"地磁设备删除成功");
            }else{
                return new ResultVo(ResultCode.FAILED,"地磁设备删除失败");
            }
        }else{
            return new ResultVo(ResultCode.FAILED,"地磁已绑定泊车位，无法删除");
        }


    }

    @Override
    public ResultVo senseNewCar(Long id,String carLicensePlate) {

//        查找地磁号对应的泊位号
        Detector detector = getById(id);
//        判断数据库有无该数据
        if (detector == null){
            Asserts.failed("数据库中无改地磁设备!");
        }
        Long berthId = detector.getBerthId();
//        修改驶入时间
        LambdaUpdateWrapper<Detector> update = Wrappers.lambdaUpdate(Detector.class);
        update.eq(Detector::getId,id);
        update.set(Detector::getEnterTime,new Date());
        update.set(Detector::getHaveCar, DeviceConstant.HAVE_CAR);
        update(update);
//        查找泊位对应的路段号
        RoadBerthDto berthDto = berthFeignClient.findParkingDtoByBerthId(berthId);
//        在redis中存储订单信息
        Map<String,Object> order = new HashMap<>();
//        生成随机订单编号
        Long oId = Long.valueOf((int)(Math.random() * 1000000));
        order.put("id",oId);
        order.put("roadId",berthDto.getRoadId());
        order.put("berthId",berthId);
        order.put("driveInTime",new Date());
        order.put("status", OrderConstant.ORDER_STATUS_UNCLAIM);
        order.put("carLicensePlate",carLicensePlate);
        String key = "tempOrder:" + "roadId:" + berthDto.getRoadId() + ":berthId:" + berthId;
        redisTemplate.opsForHash().putAll(key,order);
//        调用生产者
        OrderDto orderDto = new OrderDto();
        orderDto.setRoadId(berthDto.getRoadId());
        orderDto.setBerthId(berthId);
        orderDto.setDriveInTime(new Date());
        orderDto.setId((long) Math.round(1000000));
        orderClient.sendOrder(orderDto);
        return new ResultVo(ResultCode.SUCCESS);

    }

    @Override
    public ResultVo outOneCar(Long id) {

//        查找地磁号对应的泊位号
        Detector detector = getById(id);
//        判断数据库有无该数据
        if (detector == null){
            Asserts.failed("数据库中无该地磁设备!");
        }
        Long berthId = detector.getBerthId();
//        修改驶出时间
        LambdaUpdateWrapper<Detector> update = Wrappers.lambdaUpdate(Detector.class);
        update.eq(Detector::getId,id);
        update.set(Detector::getOutTime,new Date());
        update.set(Detector::getHaveCar,DeviceConstant.NO_CAR);
        update(update);
//        查找泊位对应的路段号
        RoadBerthDto berthDto = berthFeignClient.findParkingDtoByBerthId(berthId);
//        在redis中存储订单信息
        String key = "tempOrder:" + "roadId:" + berthDto.getRoadId() + ":berthId:" + berthId;
        Map<String,Object> order = new HashMap<>();
        order.put("driveOutTime",new Date());
        order.put("status", OrderConstant.ORDER_STATUS_UNPAY);
        order.put("submitTime",new Date());
//        调用支付接口
        order.put("amount",10);
        order.put("parkingTime",1000);
        redisTemplate.opsForHash().putAll(key,order);

//        redis中订单转实体类
        Map<String,Object> entries = redisTemplate.opsForHash().entries(key);
        ObjectMapper objectMapper = new ObjectMapper();
        Orders orders = objectMapper.convertValue(entries, Orders.class);

//        生成的订单存入数据库
        orderClient.saveOrder(orders);

        return new ResultVo(orders);
    }

    @Override
    public ResultVo unbindDevice(Integer roadId) {

        LambdaQueryWrapper<Detector> query = Wrappers.lambdaQuery(Detector.class);
        query.isNull(Detector::getBerthId);
        query.eq(Detector::getStatus,1);
        query.eq(Detector::getRoadId,roadId);

        List<Detector> detectors = this.list(query);

        return new ResultVo(detectors);
    }

    @Override
    public ResultVo bindDevice(Integer detectorId, Long berthId) {
        Detector detector = detectorMapper.selectById(detectorId);
        detector.setBerthId(berthId);

        int update = detectorMapper.updateById(detector);

        if(update>0){
            return new ResultVo(ResultCode.SUCCESS);
        }
        return new ResultVo(ResultCode.FAILED);
    }


}
